home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / game / role / moria_src_gfx_1_1.lha / source / death.c < prev    next >
C/C++ Source or Header  |  1992-04-18  |  23KB  |  943 lines

  1. /* source/death.c: code executed when player dies
  2.  
  3. Copyright (c) 1989-91 James E. Wilson, Robert A. Koeneke
  4.  
  5. This software may be copied and distributed for educational, research, and not
  6.    for profit purposes provided that this copyright and statement are included
  7.    in all such copies. */
  8.  
  9. /* Must read this before externs.h, as some global declarations use FILE. */
  10. #include <stdio.h>
  11.  
  12. #ifndef STDIO_LOADED
  13. #define STDIO_LOADED
  14. #endif
  15.  
  16. #include "config.h"
  17. #include "constant.h"
  18. #include "types.h"
  19.  
  20. #ifdef Pyramid
  21. #include <sys/time.h>
  22. #else
  23. #include <time.h>
  24. #endif
  25.  
  26. #include <ctype.h>
  27.  
  28. #ifndef USG
  29. /* only needed for Berkeley UNIX */
  30. #include <sys/param.h>
  31. #include <sys/types.h>
  32. #include <sys/file.h>
  33. #endif
  34.  
  35. #ifdef MSDOS
  36. #include <io.h>
  37. #else
  38. #if !defined(ATARIST_MWC) && !defined(MAC) && !defined(AMIGA)
  39. #if !defined(ATARIST_TC)
  40. #ifndef VMS
  41. #include <pwd.h>
  42. #else
  43. #include <file.h>
  44. #endif
  45. #endif
  46. #endif
  47. #endif
  48.  
  49. #ifdef VMS
  50. unsigned int getuid(), getgid();
  51.  
  52. #else
  53. #ifdef unix
  54. #ifdef USG
  55. unsigned short getuid(), getgid();
  56.  
  57. #else
  58. #ifndef SECURE
  59. #ifdef BSD4_3
  60. uid_t getuid(), getgid();
  61.  
  62. #else                            /* other BSD versions */
  63. int getuid(), getgid();
  64.  
  65. #endif
  66. #endif
  67. #endif
  68. #endif
  69. #endif
  70.  
  71. #ifdef USG
  72. #ifndef ATARIST_MWC
  73. #include <string.h>
  74. #ifndef VMS
  75. #ifndef ATARIST_TC
  76. #include <fcntl.h>
  77. #endif
  78. #endif
  79. #endif
  80. #else
  81. #include <strings.h>
  82. #endif
  83.  
  84. /* This must be included after fcntl.h, which has a prototype for `open' on
  85.    some systems.  Otherwise, the `open' prototype conflicts with the `topen'
  86.    declaration.  */
  87. #include "externs.h"
  88.  
  89. #ifndef BSD4_3
  90. #ifndef ATARIST_TC
  91. long lseek();
  92.  
  93. #endif                            /* ATARTIST_TC */
  94. #else
  95. off_t lseek();
  96.  
  97. #endif
  98.  
  99. #if defined(USG) || defined(VMS) || defined(atarist)
  100. #ifndef L_SET
  101. #define L_SET 0
  102. #endif
  103. #ifndef L_INCR
  104. #define L_INCR 1
  105. #endif
  106. #endif
  107.  
  108. #ifndef VMS
  109. #ifndef MAC
  110. #if defined(ultrix) || defined(USG)
  111. void exit();
  112.  
  113. #endif
  114. #endif
  115. #endif
  116.  
  117. #if defined(LINT_ARGS)
  118. static void date(char *);
  119. static char *center_string(char *, char *);
  120. static void print_tomb(void);
  121. static void kingly(void);
  122.  
  123. #endif
  124.  
  125. #ifdef ATARIST_TC
  126. /* Include this to get prototypes for standard library functions.  */
  127. #include <stdlib.h>
  128. #endif
  129.  
  130. #ifndef VMS
  131. #ifndef MAC
  132. #if !defined(ATARIST_MWC) && !defined(AMIGA)
  133. long time();
  134.  
  135. #endif
  136. #endif
  137. #endif
  138.  
  139. static void 
  140. date(day)
  141.     char *day;
  142. {
  143.     register char *tmp;
  144.  
  145. #ifdef MAC
  146.     time_t clockvar;
  147.  
  148. #else
  149.     long clockvar;
  150.  
  151. #endif
  152.  
  153. #ifdef MAC
  154.     clockvar = time((time_t *) 0);
  155. #else
  156.     clockvar = time((long *) 0);
  157. #endif
  158.     tmp = ctime(&clockvar);
  159.     tmp[10] = '\0';
  160.     (void) strcpy(day, tmp);
  161. }
  162.  
  163. /* Centers a string within a 31 character string        -JWT-     */
  164. static char *
  165. center_string(centered_str, in_str)
  166.     char *centered_str;
  167.     char *in_str;
  168. {
  169.     register int i, j;
  170.  
  171.     i = strlen(in_str);
  172.     j = 15 - i / 2;
  173.     (void) sprintf(centered_str, "%*s%s%*s", j, "", in_str, 31 - i - j, "");
  174.     return centered_str;
  175. }
  176.  
  177.  
  178. #ifndef __TURBOC__
  179. #if (defined(USG) || defined(atarist)) && !defined(VMS)
  180. #if !defined(AMIGA) && !defined(MAC) && !defined(ATARIST_TC)
  181.  
  182. #include <sys/stat.h>
  183. #include <errno.h>
  184.  
  185. /* The following code is provided especially for systems which        -CJS- have
  186.    no flock system call. It has never been tested.         */
  187.  
  188. #define LOCK_EX    1
  189. #define LOCK_SH    2
  190. #define LOCK_NB    4
  191. #define LOCK_UN    8
  192.  
  193. /* An flock HACK.  LOCK_SH and LOCK_EX are not distinguished.  DO NOT release a
  194.    lock which you failed to set!  ALWAYS release a lock you set! */
  195. static int 
  196. flock(f, l)
  197.     int f, l;
  198. {
  199.     struct stat sbuf;
  200.     char lockname[80];
  201.  
  202.     if (fstat(f, &sbuf) < 0)
  203.         return -1;
  204. #ifdef atarist
  205.     (void) sprintf(lockname, (char *) prefix_file((char *) "moria.%d"),
  206.                    sbuf.st_ino);
  207. #else
  208.     (void) sprintf(lockname, "/tmp/moria.%d", sbuf.st_ino);
  209. #endif
  210.     if (l & LOCK_UN)
  211.         return unlink(lockname);
  212.  
  213.     while (open(lockname, O_WRONLY | O_CREAT | O_EXCL, 0644) < 0) {
  214.         if (errno != EEXIST)
  215.             return -1;
  216.         if (stat(lockname, &sbuf) < 0)
  217.             return -1;
  218.         /* Locks which last more than 10 seconds get deleted. */
  219.         if (time((long *) 0) - sbuf.st_mtime > 10) {
  220.             if (unlink(lockname) < 0)
  221.                 return -1;
  222.         } else if (l & LOCK_NB)
  223.             return -1;
  224.         else
  225.             (void) sleep(1);
  226.     }
  227.     return 0;
  228. }
  229.  
  230. #endif
  231. #endif
  232. #endif
  233.  
  234. void 
  235. display_scores(show_player)
  236.     int show_player;
  237. {
  238.     register int i, rank;
  239.     high_scores score;
  240.     char input;
  241.     char string[100];
  242.     int8u version_maj, version_min, patch_level;
  243.  
  244. #if defined(unix) || defined(VMS)
  245.     int16 player_uid;
  246.  
  247. #endif
  248.  
  249. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  250. #if defined(MAC) || defined(MSDOS)
  251.     if ((highscore_fp = fopen(MORIA_TOP, "rb")) == NULL)
  252. #else
  253.     if ((highscore_fp = fopen(MORIA_TOP, "r")) == NULL)
  254. #endif
  255.     {
  256.         (void) sprintf(string, "Error opening score file \"%s\"\n", MORIA_TOP);
  257.         msg_print(string);
  258.         msg_print(CNIL);
  259.         return;
  260.     }
  261. #endif
  262.  
  263. #ifndef BSD4_3
  264.     (void) fseek(highscore_fp, (long) 0, L_SET);
  265. #else
  266.     (void) fseek(highscore_fp, (off_t) 0, L_SET);
  267. #endif
  268.  
  269.     /* Read version numbers from the score file, and check for validity.  */
  270.     version_maj = getc(highscore_fp);
  271.     version_min = getc(highscore_fp);
  272.     patch_level = getc(highscore_fp);
  273.     /* Support score files from 5.2.2 to present.  */
  274.     if (feof(highscore_fp))
  275.         /* An empty score file. */
  276.         ;
  277.     else if ((version_maj != CUR_VERSION_MAJ)
  278.              || (version_min > CUR_VERSION_MIN)
  279.              || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
  280.              || (version_min == 2 && patch_level < 2)
  281.              || (version_min < 2)) {
  282.         msg_print("Sorry. This scorefile is from a different version of \
  283. umoria.");
  284.         msg_print(CNIL);
  285. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  286.         (void) fclose(highscore_fp);
  287. #endif
  288.         return;
  289.     }
  290. #ifdef unix
  291.     player_uid = getuid();
  292. #else
  293. #ifdef VMS
  294.     player_uid = (getgid()* 1000) + getuid();
  295. #else
  296.     /* Otherwise player_uid is not used.  */
  297. #endif
  298. #endif
  299.  
  300.     /* set the static fileptr in save.c to the highscore file pointer */
  301.     set_fileptr(highscore_fp);
  302.  
  303.     rank = 1;
  304.     rd_highscore(&score);
  305.     while (!feof(highscore_fp)) {
  306.         i = 1;
  307.         clear_screen();
  308.         /* Put twenty scores on each page, on lines 2 through 21. */
  309.         while (!feof(highscore_fp) && i < 21) {
  310.             /* Only show the entry if show_player false, or if the entry
  311.                belongs to the current player.  */
  312.             if (!show_player ||
  313. #if defined(unix) || defined(VMS)
  314.                 score.uid == player_uid
  315. #else
  316.             /* Assume microcomputers should always show every entry. */
  317.                 TRUE
  318. #endif
  319.                 ){
  320.                 (void) sprintf(string,
  321.                            "%-4d%8ld %-19.19s %c %-10.10s %-7.7s%3d %-22.22s",
  322.                                rank, score.points, score.name, score.sex,
  323.                              race[score.race].trace, class[score.class].title,
  324.                                score.lev, score.died_from);
  325.                 prt(string, ++i, 0);
  326.             }
  327.             rank++;
  328.             rd_highscore(&score);
  329.         }
  330.         prt("Rank  Points Name              Sex Race       Class  Lvl Killed By"
  331.             ,0, 0);
  332.         erase_line(1, 0);
  333.         prt("[Press any key to continue.]", 23, 23);
  334.         input = inkey();
  335.         if (input == ESCAPE)
  336.             break;
  337.     }
  338. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  339.     (void) fclose(highscore_fp);
  340. #endif
  341. }
  342.  
  343.  
  344. int 
  345. duplicate_character()
  346. {
  347.     /* Only check for duplicate characters under unix and VMS.  */
  348. #if !defined (unix) && !defined(VMS)
  349.     return FALSE;
  350.  
  351. #else                            /* ! unix && ! VMS */
  352.  
  353.     high_scores score;
  354.     int8u version_maj, version_min, patch_level;
  355.     int16 player_uid;
  356.  
  357. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  358.     char string[80];
  359.  
  360. #endif
  361.  
  362. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  363. #if defined(MAC) || defined(MSDOS)
  364.     if ((highscore_fp = fopen(MORIA_TOP, "rb")) == NULL)
  365. #else
  366.     if ((highscore_fp = fopen(MORIA_TOP, "r")) == NULL)
  367. #endif
  368.     {
  369.         (void) sprintf(string, "Error opening score file \"%s\"\n", MORIA_TOP);
  370.         msg_print(string);
  371.         msg_print(CNIL);
  372.         return FALSE;
  373.     }
  374. #endif
  375.  
  376. #ifndef BSD4_3
  377.     (void) fseek(highscore_fp, (long) 0, L_SET);
  378. #else
  379.     (void) fseek(highscore_fp, (off_t) 0, L_SET);
  380. #endif
  381.  
  382.     /* Read version numbers from the score file, and check for validity.  */
  383.     version_maj = getc(highscore_fp);
  384.     version_min = getc(highscore_fp);
  385.     patch_level = getc(highscore_fp);
  386.     /* Support score files from 5.2.2 to present.  */
  387.     if (feof(highscore_fp))
  388.         /* An empty score file.  */
  389.         return FALSE;
  390.     if ((version_maj != CUR_VERSION_MAJ)
  391.         || (version_min > CUR_VERSION_MIN)
  392.         || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
  393.         || (version_min == 2 && patch_level < 2)
  394.         || (version_min < 2)) {
  395.         msg_print("Sorry. This scorefile is from a different version of \
  396. umoria.");
  397.         msg_print(CNIL);
  398. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  399.         (void) fclose(highscore_fp);
  400. #endif
  401.         return FALSE;
  402.     }
  403.     /* set the static fileptr in save.c to the highscore file pointer */
  404.     set_fileptr(highscore_fp);
  405.  
  406. #ifdef unix
  407.     player_uid = getuid();
  408. #else
  409. #ifdef VMS
  410.     player_uid = (getgid()* 1000) + getuid();
  411. #else
  412.     player_uid = 0;
  413. #endif
  414. #endif
  415.  
  416.     rd_highscore(&score);
  417.     while (!feof(highscore_fp)) {
  418.         if (score.uid == player_uid && score.birth_date == birth_date
  419.             && score.class == py.misc.pclass && score.race == py.misc.prace
  420.             && score.sex == (py.misc.male ? 'M' : 'F')
  421.             && strcmp(score.died_from, "(saved)"))
  422.             return TRUE;
  423.  
  424.         rd_highscore(&score);
  425.     }
  426. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  427.     (void) fclose(highscore_fp);
  428. #endif
  429.  
  430.     return FALSE;
  431. #endif                            /* ! unix && ! VMS */
  432. }
  433.  
  434.  
  435.  
  436. /* Prints the gravestone of the character        -RAK-     */
  437. static void 
  438. print_tomb()
  439. {
  440.     vtype str, tmp_str;
  441.     register int i;
  442.     char day[11];
  443.     register char *p;
  444.  
  445. #ifdef MAC
  446.     char func;
  447.     int ok;
  448.  
  449. #endif
  450.  
  451.     clear_screen();
  452.     put_buffer("_______________________", 1, 15);
  453.     put_buffer("/", 2, 14);
  454.     put_buffer("\\         ___", 2, 38);
  455.     put_buffer("/", 3, 13);
  456.     put_buffer("\\ ___   /   \\      ___", 3, 39);
  457.     put_buffer("/            RIP            \\   \\  :   :     /   \\", 4, 12);
  458.     put_buffer("/", 5, 11);
  459.     put_buffer("\\  : _;,,,;_    :   :", 5, 41);
  460.     (void) sprintf(str, "/%s\\,;_          _;,,,;_",
  461.                    center_string(tmp_str, py.misc.name));
  462.     put_buffer(str, 6, 10);
  463.     put_buffer("|               the               |   ___", 7, 9);
  464.     if (!total_winner)
  465.         p = title_string();
  466.     else
  467.         p = "Magnificent";
  468.     (void) sprintf(str, "| %s |  /   \\", center_string(tmp_str, p));
  469.     put_buffer(str, 8, 9);
  470.     put_buffer("|", 9, 9);
  471.     put_buffer("|  :   :", 9, 43);
  472.     if (!total_winner)
  473.         p = class[py.misc.pclass].title;
  474.     else if (py.misc.male)
  475.         p = "*King*";
  476.     else
  477.         p = "*Queen*";
  478.     (void) sprintf(str, "| %s | _;,,,;_   ____", center_string(tmp_str, p));
  479.     put_buffer(str, 10, 9);
  480.     (void) sprintf(str, "Level : %d", (int) py.misc.lev);
  481.     (void) sprintf(str, "| %s |          /    \\",
  482.                    center_string(tmp_str, str));
  483.     put_buffer(str, 11, 9);
  484.     (void) sprintf(str, "%ld Exp", py.misc.exp);
  485.     (void) sprintf(str, "| %s |          :    :", center_string(tmp_str, str));
  486.     put_buffer(str, 12, 9);
  487.     (void) sprintf(str, "%ld Au", py.misc.au);
  488.     (void) sprintf(str, "| %s |          :    :", center_string(tmp_str, str));
  489.     put_buffer(str, 13, 9);
  490.     (void) sprintf(str, "Died on Level : %d", dun_level);
  491.     (void) sprintf(str, "| %s |         _;,,,,;_", center_string(tmp_str, str));
  492.     put_buffer(str, 14, 9);
  493.     put_buffer("|            killed by            |", 15, 9);
  494.     p = died_from;
  495.     i = strlen(p);
  496.     p[i] = '.';                    /* add a trailing period */
  497.     p[i + 1] = '\0';
  498.     (void) sprintf(str, "| %s |", center_string(tmp_str, p));
  499.     put_buffer(str, 16, 9);
  500.     p[i] = '\0';                /* strip off the period */
  501.     date(day);
  502.     (void) sprintf(str, "| %s |", center_string(tmp_str, day));
  503.     put_buffer(str, 17, 9);
  504.     put_buffer("*|   *     *     *    *   *     *  | *", 18, 8);
  505.     put_buffer("________)/\\\\_)_/___(\\/___(//_\\)/_\\//__\\\\(/_|_)_______",
  506.                19, 0);
  507.  
  508.   retry:
  509.     flush();
  510. #ifdef MAC
  511.     /* On Mac, file_character() gets file name via std file dialog */
  512.     /* So, the prompt for character record cannot be made to do double duty */
  513.     put_buffer("('F' - Save record in file / 'Y' - Display record on screen \
  514. / 'N' - Abort)", 23, 0);
  515.     put_buffer("Character record [F/Y/N]?", 22, 0);
  516.     do {
  517.         func = inkey();
  518.         switch (func) {
  519.             case 'f':
  520.             case 'F':
  521.                 func = 'F';
  522.                 ok = TRUE;
  523.                 break;
  524.             case 'y':
  525.             case 'Y':
  526.                 func = 'Y';
  527.                 ok = TRUE;
  528.                 break;
  529.             case 'n':
  530.             case 'N':
  531.                 func = 'N';
  532.                 ok = TRUE;
  533.                 break;
  534.             default:
  535.                 bell();
  536.                 ok = FALSE;
  537.                 break;
  538.         }
  539.     }
  540.     while (!ok);
  541.     if (func != 'N')
  542. #else
  543.     put_buffer("(ESC to abort, return to print on screen, or file name)",
  544.                23, 0);
  545.     put_buffer("Character record?", 22, 0);
  546.     if (get_string(str, 22, 18, 60))
  547. #endif
  548.     {
  549.         for (i = 0; i < INVEN_ARRAY_SIZE; i++) {
  550.             known1(&inventory[i]);
  551.             known2(&inventory[i]);
  552.         }
  553.         calc_bonuses();
  554. #ifdef MAC
  555.         if (func == 'F') {
  556.             if (!file_character())
  557.                 goto retry;
  558.         }
  559. #else
  560.         if (str[0]) {
  561.             if (!file_character(str))
  562.                 goto retry;
  563.         }
  564. #endif
  565.         else {
  566.             clear_screen();
  567.             display_char();
  568.             put_buffer("Type ESC to skip the inventory:", 23, 0);
  569.             if (inkey()!= ESCAPE) {
  570.                 clear_screen();
  571.                 put_buffer("You are using:",0,0);
  572.                 (void) show_equip(TRUE, 0);
  573.                 inkey();
  574.                 put_buffer("You are carrying:",0,0);
  575.                 clear_from(1);
  576.                 (void) show_inven(0, inven_ctr - 1, TRUE, 0, CNIL);
  577.                 inkey();
  578.             }
  579.         }
  580.     }
  581. }
  582.  
  583.  
  584. /* Calculates the total number of points earned        -JWT-     */
  585. int32 
  586. total_points()
  587. {
  588.     int32 total;
  589.     int i;
  590.  
  591.     total = py.misc.max_exp + (100 * py.misc.max_dlv);
  592.     total += py.misc.au / 100;
  593.     for (i = 0; i < INVEN_ARRAY_SIZE; i++)
  594.         total += item_value(&inventory[i]);
  595.     total += dun_level * 50;
  596.  
  597.     /* Don't ever let the score decrease from one save to the next.  */
  598.     if (max_score > total)
  599.         return max_score;
  600.  
  601.     return total;
  602. }
  603.  
  604.  
  605. /* Enters a players name on the top twenty list        -JWT-     */
  606. static void 
  607. highscores()
  608. {
  609.     high_scores old_entry, new_entry, entry;
  610.     int i;
  611.     char *tmp;
  612.     int8u version_maj, version_min, patch_level;
  613.     long curpos;
  614.  
  615. #if defined(VMS) || defined(MSDOS) || defined(AMIGA) || defined(MAC)
  616.     char string[100];
  617.  
  618. #endif
  619.  
  620.     clear_screen();
  621.  
  622.     if (noscore)
  623.         return;
  624.  
  625.     if (panic_save == 1) {
  626.         msg_print("Sorry, scores for games restored from panic save files \
  627. are not saved.");
  628.         return;
  629.     }
  630.     new_entry.points = total_points();
  631.     new_entry.birth_date = birth_date;
  632. #ifdef unix
  633.     new_entry.uid = getuid();
  634. #else
  635. #ifdef VMS
  636.     new_entry.uid = (getgid()* 1000) + getuid();
  637. #else
  638.     new_entry.uid = 0;
  639. #endif
  640. #endif
  641.     new_entry.mhp = py.misc.mhp;
  642.     new_entry.chp = py.misc.chp;
  643.     new_entry.dun_level = dun_level;
  644.     new_entry.lev = py.misc.lev;
  645.     new_entry.max_dlv = py.misc.max_dlv;
  646.     new_entry.sex = (py.misc.male ? 'M' : 'F');
  647.     new_entry.race = py.misc.prace;
  648.     new_entry.class = py.misc.pclass;
  649.     (void) strcpy(new_entry.name, py.misc.name);
  650.     tmp = died_from;
  651.     if ('a' == *tmp) {
  652.         if ('n' == *(++tmp)) {
  653.             tmp++;
  654.         }
  655.         while (isspace(*tmp)) {
  656.             tmp++;
  657.         }
  658.     }
  659.     (void) strcpy(new_entry.died_from, tmp);
  660.  
  661.     /* First, get a lock on the high score file so no-one else tries */
  662.     /* to write to it while we are using it, on VMS and IBMPCs only one process
  663.        can have the file open at a time, so we just open it here */
  664. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  665. #if defined(MAC) || defined(MSDOS)
  666.     if ((highscore_fp = fopen(MORIA_TOP, "rb+")) == NULL)
  667. #else
  668.     if ((highscore_fp = fopen(MORIA_TOP, "r+")) == NULL)
  669. #endif
  670.     {
  671.         (void) sprintf(string, "Error opening score file \"%s\"\n", MORIA_TOP);
  672.         msg_print(string);
  673.         msg_print(CNIL);
  674.         return;
  675.     }
  676. #else
  677. #ifdef ATARIST_TC
  678.     /* 'lock' always succeeds on the Atari ST */
  679. #else
  680.     if (0 != flock((int) fileno(highscore_fp), LOCK_EX)) {
  681.         msg_print("Error gaining lock for score file");
  682.         msg_print(CNIL);
  683.         return;
  684.     }
  685. #endif
  686. #endif
  687.  
  688.     /* Search file to find where to insert this character, if uid != 0 and find
  689.        same uid/sex/race/class combo then exit without saving this score */
  690.     /* Seek to the beginning of the file just to be safe. */
  691. #ifndef BSD4_3
  692.     (void) fseek(highscore_fp, (long) 0, L_SET);
  693. #else
  694.     (void) fseek(highscore_fp, (off_t) 0, L_SET);
  695. #endif
  696.  
  697.     /* Read version numbers from the score file, and check for validity.  */
  698.     version_maj = getc(highscore_fp);
  699.     version_min = getc(highscore_fp);
  700.     patch_level = getc(highscore_fp);
  701.     /* If this is a new scorefile, it should be empty.  Write the current
  702.        version numbers to the score file.  */
  703.     if (feof(highscore_fp)) {
  704.         /* Seek to the beginning of the file just to be safe. */
  705. #ifndef BSD4_3
  706.         (void) fseek(highscore_fp, (long) 0, L_SET);
  707. #else
  708.         (void) fseek(highscore_fp, (off_t) 0, L_SET);
  709. #endif
  710.  
  711.         (void) putc(CUR_VERSION_MAJ, highscore_fp);
  712.         (void) putc(CUR_VERSION_MIN, highscore_fp);
  713.         (void) putc(PATCH_LEVEL, highscore_fp);
  714.  
  715.         /* must fseek() before can change read/write mode */
  716. #ifndef BSD4_3
  717. #ifdef ATARIST_TC
  718.         /* no fseek relative to current position allowed */
  719.         (void) fseek(highscore_fp, (long) ftell(highscore_fp), L_SET);
  720. #else
  721.         (void) fseek(highscore_fp, (long) 0, L_INCR);
  722. #endif
  723. #else
  724.         (void) fseek(highscore_fp, (off_t) 0, L_INCR);
  725. #endif
  726.     }
  727.     /* Support score files from 5.2.2 to present.  */
  728.     else if ((version_maj != CUR_VERSION_MAJ)
  729.              || (version_min > CUR_VERSION_MIN)
  730.              || (version_min == CUR_VERSION_MIN && patch_level > PATCH_LEVEL)
  731.              || (version_min == 2 && patch_level < 2)
  732.              || (version_min < 2)) {
  733.         /* No need to print a message, a subsequent call to display_scores()
  734.            will print a message.  */
  735. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  736.         (void) fclose(highscore_fp);
  737. #endif
  738.         return;
  739.     }
  740.     /* set the static fileptr in save.c to the highscore file pointer */
  741.     set_fileptr(highscore_fp);
  742.  
  743.     i = 0;
  744.     curpos = ftell(highscore_fp);
  745.     rd_highscore(&old_entry);
  746.     while (!feof(highscore_fp)) {
  747.         if (new_entry.points >= old_entry.points)
  748.             break;
  749.         /* under unix and VMS, only allow one sex/race/class combo per person,
  750.            on single user system, allow any number of entries, but try to
  751.            prevent multiple entries per character by checking for case when
  752.            birthdate/sex/race/class are the same, and died_from of scorefile
  753.            entry is "(saved)" */
  754.         else if (((new_entry.uid != 0 && new_entry.uid == old_entry.uid)
  755.              || (new_entry.uid == 0 && !strcmp(old_entry.died_from, "(saved)")
  756.                  && new_entry.birth_date == old_entry.birth_date))
  757.                  && new_entry.sex == old_entry.sex
  758.                  && new_entry.race == old_entry.race
  759.                  && new_entry.class == old_entry.class) {
  760. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  761.             (void) fclose(highscore_fp);
  762. #endif
  763.             return;
  764.         } else if (++i >= SCOREFILE_SIZE) {
  765.             /* only allow one thousand scores in the score file */
  766. #if defined(MSDOS) || defined(VMS) || defined(AMIGA) || defined(MAC)
  767.             (void) fclose(highscore_fp);
  768. #endif
  769.             return;
  770.         }
  771.         curpos = ftell(highscore_fp);
  772.         rd_highscore(&old_entry);
  773.     }
  774.  
  775.     if (feof(highscore_fp)) {
  776.         /* write out new_entry at end of file */
  777. #ifndef BSD4_3
  778.         (void) fseek(highscore_fp, curpos, L_SET);
  779. #else
  780.         (void) fseek(highscore_fp, (off_t) curpos, L_SET);
  781. #endif
  782.         wr_highscore(&new_entry);
  783.     } else {
  784.         entry = new_entry;
  785.         while (!feof(highscore_fp)) {
  786. #ifndef BSD4_3
  787. #if defined(ATARIST_TC) || defined(__TURBOC__)
  788.             /* No fseek with negative offset allowed.  */
  789.             (void) fseek(highscore_fp, (long) ftell(highscore_fp) -
  790.                          sizeof(high_scores) - sizeof(char), L_SET);
  791.  
  792. #else
  793.             (void) fseek(highscore_fp,
  794.                          -(long) sizeof(high_scores) - (long) sizeof(char),
  795.                          L_INCR);
  796.  
  797. #endif
  798. #else
  799.             (void) fseek(highscore_fp,
  800.                          -(off_t) sizeof(high_scores) - (off_t) sizeof(char),
  801.                          L_INCR);
  802.  
  803. #endif
  804.             wr_highscore(&entry);
  805.             /* under unix and VMS, only allow one sex/race/class combo per
  806.                person, on single user system, allow any number of entries, but
  807.                try to prevent multiple entries per character by checking for
  808.                case when birthdate/sex/race/class are the same, and died_from
  809.                of scorefile entry is "(saved)" */
  810.             if (((new_entry.uid != 0 && new_entry.uid == old_entry.uid)
  811.              || (new_entry.uid == 0 && !strcmp(old_entry.died_from, "(saved)")
  812.                  && new_entry.birth_date == old_entry.birth_date))
  813.                 && new_entry.sex == old_entry.sex
  814.                 && new_entry.race == old_entry.race
  815.                 && new_entry.class == old_entry.class)
  816.                 break;
  817.             entry = old_entry;
  818.             /* must fseek() before can change read/write mode */
  819. #ifndef BSD4_3
  820. #ifdef ATARIST_TC
  821.             /* No fseek relative to current position allowed.  */
  822.             (void) fseek(highscore_fp, (long) ftell(highscore_fp), L_SET);
  823. #else
  824.             (void) fseek(highscore_fp, (long) 0, L_INCR);
  825. #endif
  826. #else
  827.             (void) fseek(highscore_fp, (off_t) 0, L_INCR);
  828. #endif
  829.             curpos = ftell(highscore_fp);
  830.             rd_highscore(&old_entry);
  831.         }
  832.         if (feof(highscore_fp)) {
  833. #ifndef BSD4_3
  834.             (void) fseek(highscore_fp, curpos, L_SET);
  835. #else
  836.             (void) fseek(highscore_fp, (off_t) curpos, L_SET);
  837. #endif
  838.             wr_highscore(&entry);
  839.         }
  840.     }
  841.  
  842. #if !defined(VMS) && !defined(MSDOS) && !defined(AMIGA) && !defined(MAC)
  843. #ifdef ATARIST_TC
  844.     /* Flock never called for Atari ST with TC.  */
  845. #else
  846.     (void) flock((int) fileno(highscore_fp), LOCK_UN);
  847. #endif
  848. #else
  849.     (void) fclose(highscore_fp);
  850. #endif
  851. }
  852.  
  853.  
  854. /* Change the player into a King!            -RAK-     */
  855. static void 
  856. kingly()
  857. {
  858.     register struct misc *p_ptr;
  859.     register char *p;
  860.  
  861.     /* Change the character attributes.         */
  862.     dun_level = 0;
  863.     (void) strcpy(died_from, "Ripe Old Age");
  864.     p_ptr = &py.misc;
  865.     (void) restore_level();
  866.     p_ptr->lev += MAX_PLAYER_LEVEL;
  867.     p_ptr->au += 250000L;
  868.     p_ptr->max_exp += 5000000L;
  869.     p_ptr->exp = p_ptr->max_exp;
  870.  
  871.     /* Let the player know that he did good.     */
  872.     clear_screen();
  873.     put_buffer("#", 1, 34);
  874.     put_buffer("#####", 2, 32);
  875.     put_buffer("#", 3, 34);
  876.     put_buffer(",,,  $$$  ,,,", 4, 28);
  877.     put_buffer(",,=$   \"$$$$$\"   $=,,", 5, 24);
  878.     put_buffer(",$$        $$$        $$,", 6, 22);
  879.     put_buffer("*>         <*>         <*", 7, 22);
  880.     put_buffer("$$         $$$         $$", 8, 22);
  881.     put_buffer("\"$$        $$$        $$\"", 9, 22);
  882.     put_buffer("\"$$       $$$       $$\"", 10, 23);
  883.     p = "*#########*#########*";
  884.     put_buffer(p, 11, 24);
  885.     put_buffer(p, 12, 24);
  886.     put_buffer("Veni, Vidi, Vici!", 15, 26);
  887.     put_buffer("I came, I saw, I conquered!", 16, 21);
  888.     if (p_ptr->male)
  889.         put_buffer("All Hail the Mighty King!", 17, 22);
  890.     else
  891.         put_buffer("All Hail the Mighty Queen!", 17, 22);
  892.     flush();
  893.     pause_line(23);
  894. }
  895.  
  896.  
  897. /* Handles the gravestone end top-twenty routines    -RAK-     */
  898. void 
  899. exit_game()
  900. {
  901. #ifdef MAC
  902.     /* Prevent strange things from happening */
  903.     enablefilemenu(FALSE);
  904. #endif
  905.  
  906.     /* What happens upon dying.                -RAK-     */
  907.     msg_print(CNIL);
  908.     flush();                    /* flush all input */
  909.     nosignals();                /* Can't interrupt or suspend. */
  910.     /* If the game has been saved, then save sets turn back to -1, which
  911.        inhibits the printing of the tomb.     */
  912.     if (turn >= 0) {
  913.         if (total_winner)
  914.             kingly();
  915.         print_tomb();
  916.     }
  917.     if (character_generated && !character_saved)
  918. #ifdef MAC
  919.         (void) save_char(TRUE);    /* Save the memory at least. */
  920. #else
  921.         (void) save_char();        /* Save the memory at least. */
  922. #endif
  923.     /* add score to scorefile if applicable */
  924.     if (character_generated) {
  925.         /* Clear character_saved, strange thing to do, but it prevents inkey()
  926.            from recursively calling exit_game() when there has been an eof on
  927.            stdin detected.  */
  928.         character_saved = FALSE;
  929.         highscores();
  930.         display_scores(TRUE);
  931.     }
  932.     erase_line(23, 0);
  933.     restore_term();
  934. #ifdef MAC
  935.     /* Undo what has been done */
  936.     enablefilemenu(TRUE);
  937.     /* Long jump back into the Mac wrapper, in lieu of exit () */
  938.     goback();
  939. #else
  940.     exit(0);
  941. #endif
  942. }
  943.